package cc.xsubj.trading.world;

import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.state.StateBasedGame;

import cc.xsubj.engine.Globals;
import cc.xsubj.engine.StaticCamera;
import cc.xsubj.engine.World;
import cc.xsubj.engine.entity.Entity;
import cc.xsubj.trading.entity.InventoryItem;
import cc.xsubj.trading.inventory.Inventory;
import cc.xsubj.trading.inventory.InventoryGrid;
import cc.xsubj.trading.inventory.InventorySlot;
import cc.xsubj.trading.inventory.ItemStack;
import cc.xsubj.trading.messages.SharpText;

public class InventoryWorld extends World
{
    private InventoryGrid playerGrid;
    private InventoryGrid otherGrid;

    private InventoryItem dragging = null;
    public static String npcName = "";


    public InventoryWorld(int id, GameContainer container)
    {
        super(id, container);
    }

    @Override
    public void init(GameContainer container, StateBasedGame game)
        throws SlickException {
        super.init(container, game);
        
        setupKeymaps();
        
        this.switchToNPC("");
        
        setCamera(new StaticCamera(this, (int)(container.getWidth()/Globals.scaleX), (int)(container.getHeight()/Globals.scaleY)));
    }

    private void setupKeymaps()
    {
        define("SHIFT", Input.KEY_LSHIFT, Input.KEY_RSHIFT);
    }

    public void switchToNPC(String npcName)
    {
        InventoryWorld.npcName = npcName;

        this.clear();
        
        playerGrid = new InventoryGrid(24, 24, 5, 8);
        otherGrid = new InventoryGrid(24 + 6*(InventoryGrid.itemWidth+InventoryGrid.itemXSpacing), 24, 5, 8);
        
//        InventoryItem item;
//        for (int i = 0; i < 8; i++)
//        {
//            item = new InventoryItem(0,i*24,0, i);
//            add(item);
//        }
        
        Inventory.getPlayerInventory().addItemsToInventoryWorld(this, playerGrid);
        Inventory.getNPCInventory(npcName).addItemsToInventoryWorld(this, otherGrid);
    }
    
    @Override
	public void enter(GameContainer container, StateBasedGame game)
			throws SlickException {
		super.enter(container, game);
		
		//this.clear();
		
	}

	@Override
    public void render(GameContainer container, StateBasedGame game, Graphics g)
            throws SlickException
    {
        g.setColor(Color.gray);
        g.fillRect(0, 0, container.getWidth(), container.getHeight());
        if (Globals.debugEnabled)
        {
            playerGrid.render(g);
            otherGrid.render(g);
        }
        
        
        super.render(container, game, g);
        SharpText.drawString(""+Inventory.getPlayerInventory().getGold() + "G", g, 64, container.getHeight()/2-32);
        
        SharpText.drawString(""+Inventory.getNPCInventory(npcName).getGold() + "G", g, 256, container.getHeight()/2-32);
        
        if (dragging != null)
        {
        	//Hack to get the currently dragged item to always render on top.
        	dragging.render(container, g);
        }
    }

    @Override
    public void update(GameContainer container, StateBasedGame game, int delta)
            throws SlickException
    {
        super.update(container, game, delta);
    }
    
    @Override
    public void mouseMoved(int oldx, int oldy, int newx, int newy)
    {
        super.mouseMoved(oldx, oldy, newx, newy);
        newx /= Globals.scaleX;
        newy /= Globals.scaleY;
        oldx /= Globals.scaleX;
        oldy /= Globals.scaleY;
        
        if (dragging != null)
        {
            dragging.x = newx - dragging.width/2;
            dragging.y = newy - dragging.height/2;
        }
    }
    
    

    @Override
    public void mouseDragged(int oldx, int oldy, int newx, int newy)
    {
        super.mouseDragged(oldx, oldy, newx, newy);
        
        this.mouseMoved(oldx, oldy, newx, newy);
    }

    @Override
    public void mousePressed(int button, int x, int y)
    {
        super.mousePressed(button, x, y);
        x /= Globals.scaleX;
        y /= Globals.scaleY;
        if (button == Input.MOUSE_LEFT_BUTTON)
            leftClickHandler(x, y);
        else if (button == Input.MOUSE_RIGHT_BUTTON)
        {
            rightClickHandler(x,y);
        }
    }

    private void rightClickHandler(int x, int y)
    {
        InventoryItem item = null;
        if (dragging == null)
        {
            for(Entity e : getEntities()) {
                if (e instanceof InventoryItem) {
                    InventoryItem it = (InventoryItem) e;
                    if (it.containsPoint(x, y)) {
                        item = it;
                        break;
                    }
                }
            }
            
            if (item == null)
                return;
            
            if (item.getItemStack().getQuantity() == 1)
            {
                leftClickHandler(x, y);
                return;
            }
               
            if (true)
            {
                ItemStack itemStack = new ItemStack(item.getItemStack().getType(), 1);
                item.getItemStack().decreaseQuantity(1);
                InventoryItem newItem = new InventoryItem(x, y, itemStack);
                newItem.setInPlayerInventory(playerGrid.containsPoint(x, y));
                newItem.setBeingDragged(true);
                add(newItem);
                startDragging(newItem);
                dragging.x = x - dragging.width/2;
                dragging.y = y - dragging.height/2;
            }
        } else {
            for(Entity e : getEntities()) {
                if (e instanceof InventoryItem) {
                    InventoryItem it = (InventoryItem) e;
                    if (it.containsPoint(x, y) && it != dragging) {
                        item = it;
                        break;
                    }
                }
            }
            if (item != null && (item.isInPlayerInventory() == dragging.isInPlayerInventory()))
            {
                dragging.getItemStack().increaseQuantity(1);
                if (item.getItemStack().getQuantity() <= 1)
                {
                    //It's OK to remove from both since it can only be in one.
                    Inventory.getPlayerInventory().removeItem(item.getItemStack());
                    Inventory.getNPCInventory(npcName).removeItem(item.getItemStack());
                    remove(item);
                } else {
                    item.getItemStack().decreaseQuantity(1);
                }
            }
        }
    }

    public void leftClickHandler(int x, int y)
    {
        if (dragging == null)
        {
            for(Entity e : getEntities()) {
                if (e instanceof InventoryItem) {
                    InventoryItem item = (InventoryItem) e;
                    if (item.containsPoint(x, y)) {
                        startDragging(item);
                        dragging.updateOldPosition();
                        dragging.x = x - dragging.width/2;
                        dragging.y = y - dragging.height/2;
                        break;
                    }
                }
            }
        } else {
            if(playerGrid.containsPoint(x, y))
            {
                InventorySlot slot = playerGrid.getSlotAtPosition(x, y);
                mergeOrInsertDraggedItem(slot);
            }
            else if (otherGrid.containsPoint(x, y))
            {
                insertDraggedItemIntoOther();
            }
            else
            {
                stopDragging();
            }
        }
    }

    private void mergeOrInsertDraggedItem(InventorySlot slot)
    {
        if (slot != null)
        {
            InventoryItem item = null;
        
            for (Entity e: this.findEntityWithType("InventoryItem"))
            {
                if (e instanceof InventoryItem)
                {
                    InventoryItem tempItem = (InventoryItem) e;
                    if (tempItem.slot == slot && dragging != tempItem)
                    {
                        item = tempItem;
                        break;
                    }
                }
            }
            
            if (item == null)
            {
                insertDraggedItemIntoPlayerSlot(slot);
                return;
            }
            
            if (item.getItemStack().getType() == dragging.getItemStack().getType() && dragging.isInPlayerInventory() && item.isInPlayerInventory())
            {
                item.getItemStack().increaseQuantity(dragging.getItemStack().getQuantity());
                this.remove(dragging);
                stopDragging();
            }
        } else {
            stopDragging();
        }
    }

    public void startDragging(InventoryItem item)
    {
        dragging = item;
        dragging.setBeingDragged(true);
        
        Inventory.getPlayerInventory().removeItem(dragging.getItemStack());
        Inventory.getNPCInventory(npcName).removeItem(dragging.getItemStack());
    }

    public void stopDragging()
    {
        dragging.restoreOldPosition();
        dragging.setBeingDragged(false);
        dragging = null;
    }
    
    public void insertDraggedItemIntoPlayerSlot(InventorySlot slot)
    {
        if (slot != null)
        {
            for (Entity e: this.findEntityWithType("InventoryItem"))
            {
                if (e instanceof InventoryItem)
                {
                    InventoryItem item = (InventoryItem) e;
                    if (item.slot == slot && dragging != item)
                    {
                        return;
                    }
                }
            }
            if(dragging.isInPlayerInventory())
                Inventory.getPlayerInventory().insertItem(dragging.getItemStack(), playerGrid.getInventoryIndexFromCoords(slot.x, slot.y));
            else
            {
                int price = Inventory.getNPCInventory(npcName).getWillSellPrice(dragging.getItemStack().getType()) * dragging.getItemStack().getQuantity();
                boolean hasEnoughToBuy = Inventory.getPlayerInventory().withdraw(price);
                if(hasEnoughToBuy)
                {
                    Inventory.getNPCInventory(npcName).deposit(price);
                    Inventory.getPlayerInventory().insertItem(dragging.getItemStack(), playerGrid.getInventoryIndexFromCoords(slot.x, slot.y));
                    dragging.setInPlayerInventory(true);
                } 
                else 
                {
                    stopDragging();
                    return;
                }
            }
            
            
            dragging.setNewPosition(slot.getBounds().getX(), slot.getBounds().getY());
            dragging.slot = slot;
            stopDragging();
        }
    }
    
    public void insertDraggedItemIntoOther()
    {
        if(!dragging.isInPlayerInventory())
        {
            insertDraggedIntoOther();
            return;
        } else {
            Inventory npcInv = Inventory.getNPCInventory(npcName);
            int price = npcInv.getWillBuyPrice(dragging.getItemStack().getType()) * dragging.getItemStack().getQuantity();
            boolean hasEnoughToBuy = npcInv.withdraw(price);
            if (hasEnoughToBuy)
            {
                int insertedIndex = insertDraggedIntoOther();
                if (insertedIndex != -1)
                {
                    Inventory.getPlayerInventory().deposit(price);
                    return;
                }
            } else {
                stopDragging();
                return;
            }
        }
        
    }

    public int insertDraggedIntoOther()
    {
        int insertedIndex = Inventory.getNPCInventory(npcName).addItem(dragging.getItemStack());
        if (insertedIndex != -1)
        {
            InventorySlot slot = otherGrid.getSlots().get(insertedIndex);
            dragging.setNewPosition(slot.getBounds().getX(), slot.getBounds().getY());
            dragging.slot = slot;
            dragging.setInPlayerInventory(false);
            stopDragging();
        }
        return insertedIndex;
    }

//    @Override
//    public void mouseReleased(int button, int x, int y)
//    {
//        super.mouseReleased(button, x, y);
//        x /= Globals.scaleX;
//        y /= Globals.scaleY;
//        dragging.snapToGrid();
//        dragging = null;
//    }
}
